home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / servic.zip / SIMPLE.C < prev   
C/C++ Source or Header  |  1993-02-08  |  14KB  |  455 lines

  1. ///////////////////////////////////////////////////////
  2. //
  3. //  Service.c --
  4. //      main program for Service sample.
  5. //
  6. //      This service simply opens a named pipe
  7. //      (called \\.\pipe\simple), and reads from it.
  8. //      It then mangles the data passed in and writes
  9. //      the result back out to the pipe.
  10. //
  11. //      The simple service will respond to the basic
  12. //      service controller functions, i.e. Start,
  13. //      Stop, and Pause.
  14. //
  15. //      Copyright 1993, Microsoft Corp.
  16. //      All Rights Reserved
  17. //
  18. //  history:
  19. //      who         when            what
  20. //      ---         ----            ----
  21. //      davidbro    2/2/93          creation
  22. //
  23.  
  24. #include <windows.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27.  
  28. // this event is signalled when the
  29. //  worker thread ends
  30. //
  31. HANDLE                  hServDoneEvent = NULL;
  32. SERVICE_STATUS          ssStatus;       // current status of the service
  33.  
  34. SERVICE_STATUS_HANDLE   sshStatusHandle;
  35. DWORD                   dwGlobalErr;
  36. DWORD                   TID = 0;
  37. HANDLE                  threadHandle = NULL;
  38. HANDLE                  pipeHandle;
  39.  
  40.  
  41. //  declare the service threads:
  42. //
  43. VOID    service_main(DWORD dwArgc, LPTSTR *lpszArgv);
  44. VOID    service_ctrl(DWORD dwCtrlCode);
  45. BOOL    ReportStatusToSCMgr(DWORD dwCurrentState,
  46.                             DWORD dwWin32ExitCode,
  47.                             DWORD dwCheckPoint,
  48.                             DWORD dwWaitHint);
  49. VOID    StopSampleService(LPTSTR lpszMsg);
  50. VOID    die(char *reason);
  51. VOID    worker_thread(VOID *notUsed);
  52. VOID    StopSimpleService(LPTSTR lpszMsg);
  53.  
  54.  
  55.  
  56. //  main() --
  57. //      all main does is call StartServiceCtrlDispatcher
  58. //      to register the main service thread.  When the
  59. //      API returns, the service has stopped, so exit.
  60. //
  61. VOID
  62. main()
  63. {
  64.     SERVICE_TABLE_ENTRY dispatchTable[] = {
  65.         { TEXT("SimpleService"), (LPSERVICE_MAIN_FUNCTION)service_main },
  66.         { NULL, NULL }
  67.     };
  68.  
  69.     if (!StartServiceCtrlDispatcher(dispatchTable)) {
  70.         StopSimpleService("StartServiceCtrlDispatcher failed.");
  71.     }
  72. }
  73.  
  74.  
  75.  
  76. //  service_main() --
  77. //      this function takes care of actually starting the service,
  78. //      informing the service controller at each step along the way.
  79. //      After launching the worker thread, it waits on the event
  80. //      that the worker thread will signal at its termination.
  81. //
  82. VOID
  83. service_main(DWORD dwArgc, LPTSTR *lpszArgv)
  84. {
  85.     DWORD                   dwWait;
  86.     PSECURITY_DESCRIPTOR    pSD;
  87.     SECURITY_ATTRIBUTES     sa;
  88.  
  89.     // register our service control handler:
  90.     //
  91.     sshStatusHandle = RegisterServiceCtrlHandler(
  92.                                     TEXT("SimpleService"),
  93.                                     service_ctrl);
  94.  
  95.     if (!sshStatusHandle)
  96.         goto cleanup;
  97.  
  98.     // SERVICE_STATUS members that don't change in example
  99.     //
  100.     ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  101.     ssStatus.dwServiceSpecificExitCode = 0;
  102.  
  103.  
  104.     // report the status to Service Control Manager.
  105.     //
  106.     if (!ReportStatusToSCMgr(
  107.         SERVICE_START_PENDING, // service state
  108.         NO_ERROR,              // exit code
  109.         1,                     // checkpoint
  110.         3000))                 // wait hint
  111.         goto cleanup;
  112.  
  113.     // create the event object. The control handler function signals
  114.     // this event when it receives the "stop" control code.
  115.     //
  116.     hServDoneEvent = CreateEvent(
  117.         NULL,    // no security attributes
  118.         TRUE,    // manual reset event
  119.         FALSE,   // not-signalled
  120.         NULL);   // no name
  121.  
  122.     if (hServDoneEvent == (HANDLE)NULL)
  123.         goto cleanup;
  124.  
  125.     // report the status to the service control manager.
  126.     //
  127.     if (!ReportStatusToSCMgr(
  128.         SERVICE_START_PENDING, // service state
  129.         NO_ERROR,              // exit code
  130.         2,                     // checkpoint
  131.         3000))                 // wait hint
  132.         goto cleanup;
  133.  
  134.     // create a security descriptor that allows anyone to write to
  135.     //  the pipe...
  136.     //
  137.     pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
  138.                 SECURITY_DESCRIPTOR_MIN_LENGTH);
  139.  
  140.     if (pSD == NULL) {
  141.         StopSimpleService("LocalAlloc pSD failed");
  142.         return;
  143.     }
  144.  
  145.     if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
  146.         StopSimpleService("InitializeSecurityDescriptor failed");
  147.         LocalFree((HLOCAL)pSD);
  148.         return;
  149.     }
  150.  
  151.     // add a NULL disc. ACL to the security descriptor.
  152.     //
  153.     if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE)) {
  154.         StopSimpleService("SetSecurityDescriptorDacl failed");
  155.         LocalFree((HLOCAL)pSD);
  156.         return;
  157.     }
  158.  
  159.     sa.nLength = sizeof(sa);
  160.     sa.lpSecurityDescriptor = pSD;
  161.     sa.bInheritHandle = TRUE;       // why not...
  162.  
  163.     // open our named pipe...
  164.     //
  165.     pipeHandle = CreateNamedPipe(
  166.                     "\\\\.\\pipe\\simple",  // name of pipe
  167.                     PIPE_ACCESS_DUPLEX,     // pipe open mode
  168.                     PIPE_TYPE_MESSAGE |
  169.                     PIPE_READMODE_MESSAGE |
  170.                     PIPE_WAIT,              // pipe IO type
  171.                     1,                      // number of instances
  172.                     0,                      // size of outbuf (0 == allocate as necessary)
  173.                     0,                      // size of inbuf
  174.                     1000,                   // default time-out value
  175.                     &sa);                   // security attributes
  176.  
  177.     if (!pipeHandle) {
  178.         StopSimpleService("CreateNamedPipe");
  179.         LocalFree((HLOCAL)pSD);
  180.         return;
  181.     }
  182.  
  183.     // start the thread that performs the work of the service.
  184.     //
  185.     threadHandle = CreateThread(
  186.                     NULL,       // security attributes
  187.                     0,          // stack size (0 means inherit parent's stack size)
  188.                     (LPTHREAD_START_ROUTINE)worker_thread,
  189.                     NULL,       // argument to thread
  190.                     0,          // thread creation flags
  191.                     &TID);      // pointer to thread ID
  192.  
  193.     if (!threadHandle)
  194.         goto cleanup;
  195.  
  196.     // report the status to the service control manager.
  197.     //
  198.     if (!ReportStatusToSCMgr(
  199.         SERVICE_RUNNING, // service state
  200.         NO_ERROR,        // exit code
  201.         0,               // checkpoint
  202.         0))              // wait hint
  203.         goto cleanup;
  204.  
  205.     // wait indefinitely until hServDoneEvent is signaled.
  206.     //
  207.     dwWait = WaitForSingleObject(
  208.         hServDoneEvent,  // event object
  209.         INFINITE);       // wait indefinitely
  210.  
  211. cleanup:
  212.  
  213.     if (hServDoneEvent != NULL)
  214.         CloseHandle(hServDoneEvent);
  215.  
  216.  
  217.     // try to report the stopped status to the service control manager.
  218.     //
  219.     if (sshStatusHandle != NULL)
  220.         (VOID)ReportStatusToSCMgr(
  221.                             SERVICE_STOPPED,
  222.                             dwGlobalErr,
  223.                             0,
  224.                             0);
  225.  
  226.     // When SERVICE MAIN FUNCTION returns in a single service
  227.     // process, the StartServiceCtrlDispatcher function in
  228.     // the main thread returns, terminating the process.
  229.     //
  230.     return;
  231. }
  232.  
  233.  
  234.  
  235. //  service_ctrl() --
  236. //      this function is called by the Service Controller whenever
  237. //      someone calls ControlService in reference to our service.
  238. //
  239. VOID
  240. service_ctrl(DWORD dwCtrlCode)
  241. {
  242.     DWORD  dwState = SERVICE_RUNNING;
  243.  
  244.     // Handle the requested control code.
  245.     //
  246.     switch(dwCtrlCode) {
  247.  
  248.         // Pause the service if it is running.
  249.         //
  250.         case SERVICE_CONTROL_PAUSE:
  251.  
  252.             if (ssStatus.dwCurrentState == SERVICE_RUNNING) {
  253.                 SuspendThread(threadHandle);
  254.                 dwState = SERVICE_PAUSED;
  255.             }
  256.             break;
  257.  
  258.         // Resume the paused service.
  259.         //
  260.         case SERVICE_CONTROL_CONTINUE:
  261.  
  262.             if (ssStatus.dwCurrentState == SERVICE_PAUSED) {
  263.                 ResumeThread(threadHandle);
  264.                 dwState = SERVICE_RUNNING;
  265.             }
  266.             break;
  267.  
  268.         // Stop the service.
  269.         //
  270.         case SERVICE_CONTROL_STOP:
  271.  
  272.             dwState = SERVICE_STOP_PENDING;
  273.  
  274.             // Report the status, specifying the checkpoint and waithint,
  275.             //  before setting the termination event.
  276.             //
  277.             ReportStatusToSCMgr(
  278.                     SERVICE_STOP_PENDING, // current state
  279.                     NO_ERROR,             // exit code
  280.                     1,                    // checkpoint
  281.                     3000);                // waithint
  282.  
  283.             SetEvent(hServDoneEvent);
  284.             return;
  285.  
  286.         // Update the service status.
  287.         //
  288.         case SERVICE_CONTROL_INTERROGATE:
  289.             break;
  290.  
  291.         // invalid control code
  292.         //
  293.         default:
  294.             break;
  295.  
  296.     }
  297.  
  298.     // send a status response.
  299.     //
  300.     ReportStatusToSCMgr(dwState, NO_ERROR, 0, 0);
  301. }
  302.  
  303.  
  304.  
  305. //  worker_thread() --
  306. //      this function does the actual nuts and bolts work that
  307. //      the service requires.  It will also Pause or Stop when
  308. //      asked by the service_ctrl function.
  309. //
  310. VOID
  311. worker_thread(VOID *notUsed)
  312. {
  313.     char                    inbuf[80];
  314.     char                    outbuf[80];
  315.     BOOL                    ret;
  316.     DWORD                   bytesRead;
  317.     DWORD                   bytesWritten;
  318.  
  319.     // okay, our pipe has been creating, let's enter the simple
  320.     //  processing loop...
  321.     //
  322.     while (1) {
  323.  
  324.         // wait for a connection...
  325.         //
  326.         ConnectNamedPipe(pipeHandle, NULL);
  327.  
  328.         // grab whatever's coming through the pipe...
  329.         //
  330.         ret = ReadFile(
  331.                     pipeHandle,     // file to read from
  332.                     inbuf,          // address of input buffer
  333.                     sizeof(inbuf),  // number of bytes to read
  334.                     &bytesRead,     // number of bytes read
  335.                     NULL);          // overlapped stuff, not needed
  336.  
  337.         if (!ret)
  338.             // pipe's broken... go back and reconnect
  339.             //
  340.             continue;
  341.  
  342.         // munge the string
  343.         //
  344.         sprintf(outbuf, "foo! [%s]", inbuf);
  345.  
  346.         // send it back out...
  347.         //
  348.         ret = WriteFile(
  349.                     pipeHandle,     // file to write to
  350.                     outbuf,         // address of output buffer
  351.                     sizeof(outbuf), // number of bytes to write
  352.                     &bytesWritten,  // number of bytes written
  353.                     NULL);          // overlapped stuff, not needed
  354.  
  355.         if (!ret)
  356.             // pipe's broken... go back and reconnect
  357.             //
  358.             continue;
  359.  
  360.         // drop the connection...
  361.         //
  362.         DisconnectNamedPipe(pipeHandle);
  363.     }
  364. }
  365.  
  366.  
  367.  
  368. // utility functions...
  369.  
  370.  
  371.  
  372. // ReportStatusToSCMgr() --
  373. //      This function is called by the ServMainFunc() and
  374. //      ServCtrlHandler() functions to update the service's status
  375. //      to the service control manager.
  376. //
  377. BOOL
  378. ReportStatusToSCMgr(DWORD dwCurrentState,
  379.                     DWORD dwWin32ExitCode,
  380.                     DWORD dwCheckPoint,
  381.                     DWORD dwWaitHint)
  382. {
  383.     BOOL fResult;
  384.  
  385.     // Disable control requests until the service is started.
  386.     //
  387.     if (dwCurrentState == SERVICE_START_PENDING)
  388.         ssStatus.dwControlsAccepted = 0;
  389.     else
  390.         ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  391.             SERVICE_ACCEPT_PAUSE_CONTINUE;
  392.  
  393.     // These SERVICE_STATUS members are set from parameters.
  394.     //
  395.     ssStatus.dwCurrentState = dwCurrentState;
  396.     ssStatus.dwWin32ExitCode = dwWin32ExitCode;
  397.     ssStatus.dwCheckPoint = dwCheckPoint;
  398.  
  399.     ssStatus.dwWaitHint = dwWaitHint;
  400.  
  401.     // Report the status of the service to the service control manager.
  402.     //
  403.     if (!(fResult = SetServiceStatus(
  404.                 sshStatusHandle,    // service reference handle
  405.                 &ssStatus))) {      // SERVICE_STATUS structure
  406.  
  407.         // If an error occurs, stop the service.
  408.         //
  409.         StopSimpleService("SetServiceStatus");
  410.     }
  411.     return fResult;
  412. }
  413.  
  414.  
  415.  
  416. // The StopSimpleService function can be used by any thread to report an
  417. //  error, or stop the service.
  418. //
  419. VOID
  420. StopSimpleService(LPTSTR lpszMsg)
  421. {
  422.     CHAR    chMsg[256];
  423.     HANDLE  hEventSource;
  424.     LPTSTR  lpszStrings[2];
  425.  
  426.     dwGlobalErr = GetLastError();
  427.  
  428.     // Use event logging to log the error.
  429.     //
  430.     hEventSource = RegisterEventSource(NULL,
  431.                             TEXT("SimpleService"));
  432.  
  433.     sprintf(chMsg, "SimpleService error: %d", dwGlobalErr);
  434.     lpszStrings[0] = chMsg;
  435.     lpszStrings[1] = lpszMsg;
  436.  
  437.     if (hEventSource != NULL) {
  438.         ReportEvent(hEventSource, // handle of event source
  439.             EVENTLOG_ERROR_TYPE,  // event type
  440.             0,                    // event category
  441.             0,                    // event ID
  442.             NULL,                 // current user's SID
  443.             2,                    // strings in lpszStrings
  444.             0,                    // no bytes of raw data
  445.             lpszStrings,          // array of error strings
  446.             NULL);                // no raw data
  447.  
  448.         (VOID) DeregisterEventSource(hEventSource);
  449.     }
  450.  
  451.     // Set a termination event to stop SERVICE MAIN FUNCTION.
  452.     //
  453.     SetEvent(hServDoneEvent);
  454. }
  455.